package ru.chaykin.measures;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.opengles.GL10;

import ru.chaykin.graphdrawers.Pen;
import ru.chaykin.primitives.Point;


/**
 * Класс для измерения углов
 * @author kirill
 */
public class Goniometry extends Measure {

	private static final int PNTS_REQUEST = 3; //Необходимое для расчета угла число точек

	private Pen pen;
	private List<Point> lines = new ArrayList<Point>();	//Линии, образующие угол
	
	public Goniometry(Pen pen, float radius) {
		this.pen=pen;
		this.radius = radius;
		startSize = radius;
		ByteBuffer bb = ByteBuffer.allocateDirect(12 * PNTS_REQUEST);
		bb.order(ByteOrder.nativeOrder());
		linesBuff = bb.asFloatBuffer();
		initMarksBuff();
	}
	
	protected void initMarksBuff() {
		for (int i = 0; i< PNTS_REQUEST; i++) {
			ByteBuffer bb = ByteBuffer.allocateDirect(12 * ANGLES);
			bb.order(ByteOrder.nativeOrder());
			marksBuffs.add(bb.asFloatBuffer());
		}
	}
	
	private void buildCircle(FloatBuffer marksBuff, Point p, float radius) {
		marksBuff.position(0);
		for (int i = 0; i < ANGLES; i++) {
			marksBuff.put(p.getx() + (float) (radius * Math.sin(i * 2 * Math.PI / ANGLES)));
			marksBuff.put(p.gety() + (float) (radius * Math.cos(i * 2 * Math.PI / ANGLES)));
			marksBuff.put(Point.z);
		}
		marksBuff.position(0);
	}

	public void add(Point p) {
		if (lines.size() < PNTS_REQUEST) {
			linesBuff.position(3 * lines.size());
			linesBuff.put(p.getx());
			linesBuff.put(p.gety());
			linesBuff.put(Point.z);
			linesBuff.position(0);
			buildCircle(marksBuffs.get(lines.size()),p, radius);
			lines.add(p);
		}
		else {
			lines.clear();
			linesBuff.clear();
			marksBuffs.clear();
			initMarksBuff();
			add(p); //Типа рекурсия...
		}
	}
	
	private  void fillMarks() {
		initMarksBuff();
		for (int i = 0; i < lines.size(); i++) {
			buildCircle(marksBuffs.get(i), lines.get(i), radius);
		}
	}

	public void draw(GL10 gl) {
		if (linesBuff != null) {	//Словил NullPointerException. Вызвано неправильным порядком вызова обработчиков
			pen.applayToScene(gl);
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, linesBuff);
			gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, lines.size());
			for (int i = 0; i < lines.size(); i++) {
				gl.glVertexPointer(3, GL10.GL_FLOAT, 0, marksBuffs.get(i));
				gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, ANGLES);
			}
		}
	}

	public void zoom(float m) {
		radius = startSize * m;
		fillMarks();
	}
	
	public String getMeasuredData() {
		if (lines.size() == PNTS_REQUEST) {
			// квадрат длины вектора а
			double va2 = Math.pow(lines.get(0).getx() - lines.get(1).getx(), 2) + Math.pow(lines.get(0).gety() - lines.get(1).gety(), 2);
			double vb2 = Math.pow(lines.get(2).getx() - lines.get(1).getx(), 2) + Math.pow(lines.get(2).gety() - lines.get(1).gety(), 2);
			double mul_ab = (lines.get(0).getx() - lines.get(1).getx()) * (lines.get(2).getx() - lines.get(1).getx()) +
							(lines.get(0).gety() - lines.get(1).gety()) * (lines.get(2).gety() - lines.get(1).gety());
			double a_rad = Math.acos(mul_ab / Math.sqrt(va2 * vb2));
			double a_grad = 360 * a_rad / (2 * Math.PI);
			int g = (int) a_grad;
			int m = (int)((a_grad - g) * 60);
			int s = (int)((((a_grad - g) * 60) - m) * 60 * 100);
			return g + "°" + m + "'" + s / 100.0 + "\"";
		}
		return "";
	}
}
